/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package polybook.model;

import java.io.IOException;
import java.util.ArrayList;
import polybook.utils.ProcessCallBackable;
import polybook.utils.RandomUtils;

/**
 *  Cette classe représente le réseau. Génération avec une complexité n².
 * 
 */
public class NetworkPersonLinked extends Network {

    /* Constructeur par défaut. */
    public NetworkPersonLinked(ProcessCallBackable callbackObject) {
        this.container = new ArrayList<Person>();
        this.callbacker = callbackObject;
    }
    
    public NetworkPersonLinked() {
        this(null);
    }

    /**
     * Constructeur du Kernel, initialisation de la liste alÃ©atoire de personne.
     * Création des liens d'amitiÃ©s entre les personnes lors de l'initialisation
     * en comparaison de la probabilitÃ© passÃ©e en paramÃ¨tres.
     * 
     * @param numberPeople Nombre de personnes Ã  crÃ©er lors de l'initialisation
     * du kernel.
     */
    public NetworkPersonLinked(int numberPeople) throws IOException {
        this(null);
        initNetwork(numberPeople);
    }
    
    /**
     * Constructeur avec gestion d'un callback
     * @param numberPeople
     * @throws IOException 
     */
    public NetworkPersonLinked(int numberPeople, ProcessCallBackable callbackObject) throws IOException {
        this(callbackObject);
        initNetwork(numberPeople);
    }

    /**
     * Cette methode ajoute un nombre de personnes passe en parametre au reseau 
     * existant. Le reseau est compilation et les liens d'amities ajoutes en
     * fonction de la probabilite de chaque personne du reseau.
     * 
     * @param addNb - Nombre de personne Ã  ajouter au rÃ©seau.
     */
    @Override
    public void addPersonAtNetwork(int addNb) throws IOException, IllegalAccessException {
        if (this.container.isEmpty()) {
            throw new IllegalAccessException("Attention le réseau doit etre initialise avant d'ajouter une personne");
        }

        int taille = this.container.size();
        for (int i = taille; i < addNb + taille; i++) {
            String pseudo = RandomUtils.generateString(5, 15, false) + i;
            Person onePerson2 = new Person(pseudo, true, this);
            addLink(onePerson2);
            this.container.add(onePerson2);
            
            if(this.callbacker != null) {
                this.callbacker.callback((float) (i-taille) / (float) addNb);
            }
        }
    }
    

    /**
     * Cette mÃ©thode test la personne passÃ©e en paramÃ¨tres avec toutes les
     * personnes du rÃ©seau. Elle crÃ©e des liens d'amitiÃ©s selon le pourcentage
     * calculÃ©.
     * 
     * @param Person La personne que l'on va comparer Ã  tout le reseau.
     */
    @Override
    protected void addLink(Person onePerson2) {
        for (Person onePerson3 : this.container) {
            //On ne vérifie pas si la personne est différente de la personne
            //que l'on vas tester car on ne la pas encore ajoutée au reseau.
            double probaAleatoire = Math.random();
            float probaGenerated = onePerson3.calculProba();

            if (probaAleatoire <= probaGenerated) {
                onePerson2.linkTo(onePerson3);
                this.nbLink++;
            }
        }
    }
    
    /**
     * Ajout des liens lors de l'initialisation. La probabilité n'est pas 
     * calculée.
     * @param onePerson2
     * @param init 
     */
    protected void addLinkInit(Person onePerson2, boolean init) {

        for (Person onePerson3 : this.container) {
            //On ne vérifie pas si la personne est différente de la personne
            //que l'on vas tester car on ne la pas encore ajoutée au reseau.
            double probaAleatoire = Math.random();

            float probaGenerated = Network.INIT_PROBA;

            if (probaAleatoire <= probaGenerated) {

                onePerson2.linkTo(onePerson3);
                this.nbLink++;
            }

        }
    }

    /**
     * Supprime les diffÃ©rents liens existants entre la personne passÃ©e en paramÃ¨tres 
     * et les autres membres du rÃ©seaux.
     * 
     * @param String Le pseudo de la personne Ã  dÃ©tacher du rÃ©seaux
     */
    @Override
    public void deleteLink(Person personToDelete) throws IllegalArgumentException {
        if (!this.container.contains(personToDelete)) {
            throw new IllegalArgumentException("Aucune personne du rÃ©seau n'a ce pseudo");
        }
        personToDelete.unlinkAll();
        this.container.remove(personToDelete);
    }

    //Return le nombre de lien du reseau.
    @Override
    public int getNbLink() {
        return this.nbLink;
    }

    protected void initNetwork(int numberPeople) throws IOException {
        for (int i = 1; i <= numberPeople; i++) {
            String pseudo = RandomUtils.generateString(5, 15, false) + i;
            Person person = new Person(pseudo, true, this);
            addLinkInit(person, true);
            container.add(person);
        }
    }
}